#ifndef __HTTP_CONNECTION_H__
#define __HTTP_CONNECTION_H__

#include <sys/epoll.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <memory.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include "locker.h"

class http_conn
{
public:
    static int m_epollfd;    // 所有的socket上的事件都被注册到同一个epollfd上
    static int m_user_count; // 统计用户数量
    static const int READ_BUFFER_SIZE = 2048;
    static const int WRITE_BUFFER_SIZE = 1024;
    static const int MAX_FILE_NAME_SIZE = 255;


    // 请求方法
    enum METHOD
    {
        GET = 0,
        POST,
        HEAD,
        PUT,
        DELETE,
        TRACE,
        OPTIONS,
        CONNECT
    };

    // 主状态机状态
    enum CHECK_STATE
    {
        CHECK_STATE_REQUESTLINE = 0, // 正在解析请求行
        CHECK_STATE_HEADER,          // 正在解析请求头
        CHECK_STATE_CONTENT          // 正在解析请求体
    };

    enum HTTP_CODE
    {
        NO_REQUEST = 0,   // 请求不完整，需要继续读区数据
        GET_REQUEST,      // 表示获得了一个完整的客户请求
        BAD_REQUEST,      // 表示客户请求语法错误
        NO_RESOURCE,      // 表示服务器没有资源
        FORIDDEN_REQUEST, // 表示客户对资源没有足够的访问权限
        FILE_REQUEST,     // 文件请求，获取文件成功
        INTERNAL_ERROR,   // 表示服务器内部错误
        CLOSED_CONNECTION // 表示客户端已经关闭连接
    };

    // 从状态机状态
    enum LINE_STATUS
    {
        LINE_OK = 0, // 读到一个完整的请求行
        LINE_BAD,    // 行出错
        LINE_OPEN    // 行数据不完整
    };

    http_conn();
    ~http_conn();

    void process();                                 // 处理客户业务
    void init(int sockfd, const sockaddr_in &addr); // 初始化连接
    void close_conn();                              // 关闭连接

    bool read();  // 非阻塞读
    bool write(); // 非阻塞写

    HTTP_CODE process_read();
    bool process_wirte(HTTP_CODE http_code);

    HTTP_CODE parse_request_line(char *text); // 解析http请求首行
    HTTP_CODE parse_headers(char *text);      // 解析请求头
    HTTP_CODE parse_content(char *text);      // 解析请求体

    LINE_STATUS parse_line();

private:
    void init();

    inline char* get_line() {
        return m_read_buf + m_start_line;
    }

    HTTP_CODE do_request();

    void unmap();

    bool add_response(const char* format, ...);
    bool add_content( const char* content );
    bool add_content_type();
    bool add_status_line( int status, const char* title );
    bool add_headers( int content_length );
    bool add_content_length( int content_length );
    bool add_linger();
    bool add_blank_line();

private:
    int m_sockfd;                      // 该http连接的文件描述符
    sockaddr_in m_address;             // 通信的address地址
    char m_read_buf[READ_BUFFER_SIZE]; // 读缓冲
    int m_read_idx;                    // 标记已读数据位置
    char m_write_buf[WRITE_BUFFER_SIZE];
    int m_write_idx;

    int m_check_idx;  // 当前解析的字符在缓冲区的位置
    int m_start_line; // 当前正在解析的行的起始位置

    CHECK_STATE m_check_state; // 主状态机当前状态

    char* m_url;
    char* m_version;
    METHOD m_method;
    char* m_host;
    bool m_linger;
    int m_content_length;

    char m_real_file[MAX_FILE_NAME_SIZE];
    struct stat m_file_stat; //文件状态
    struct iovec m_iv[2]; //写操作
    int m_iv_count;
    char* m_file_address;

    int bytes_to_send;//需要发送的字节数
    int bytes_have_send;//已经发送的字节数
};

#endif